package Bench::Test::Remote;

use 5.008004;
use strict;
use warnings;

use Cwd;
use File::Basename;
use GRID::Machine;
use Data::Dumper;

our $VERSION = '0.01';

our $GET_RESULT  = \&default_get_result;
our $SAVE_RESULT = \&default_save_result;

sub error_no_param {
   my $param = shift;
   die "You must set " . $param . " parameter in " . __PACKAGE__ . " constructor\n";
}

#============================================================================== 
# Object Constructor.
# - Inputs:  Classname and parameter hash including:
#
#    * WORKDIR: Path to saved base files
#
# - Outputs: The blessed reference
#============================================================================== 
sub new {
   my ($class, %params) = @_;
   
   my $machine    = $params{MACHINE};
   my $workdir    = $params{WORKDIR}    or error_no_param("WORKDIR");
   my $executable = $params{EXECUTABLE} or error_no_param("EXECUTABLE");

   unless (defined($machine) and ref($machine) =~ /GRID::Machine/) {
      my $host  = $params{HOST} or die error_no_param ("HOST");
   }
 
   return bless {
      HOST        => $params{HOST},
      WORKDIR     => $workdir,
      EXECUTABLE  => $executable,
      BASEDIR     => $params{BASEDIR},
      OUTPUTFILE  => $params{OUTPUTFILE},
      PREAMBLE    => $params{PREAMBLE}    || sub { return 1 },
      POSTAMBLE   => $params{POSTAMBLE}   || sub { 1 },
      GET_RESULT  => $params{GET_RESULT}  || $GET_RESULT,
      SAVE_RESULT => $params{SAVE_RESULT} || $SAVE_RESULT,
      CURRENTDIR  => cwd,
      MACHINE     => $machine,
   }, $class;
}

sub connect {
   my $self = shift;

   my $machine = $self->{MACHINE};

   unless (defined($machine) and ref($machine) =~ /GRID::Machine/) {
      my $host  = $self->{HOST};
      $machine = GRID::Machine->new (
                                   host       => $host,
                                   sendstdout => 1,
                                );
   }
   
   $machine->sub(
      execute_file   => q{
         my ($exec, $params) = @_;
         if (-x $exec) {
            $exec = "./$exec";
         }
         my $output = `$exec $params`;
         return $output;
      },
      can_read  => q{
         my ($file) = @_;
         return (-r $file);
      },
      read_file => q{
         my ($file) = @_;
         local $/ = undef;
         open FILE, "< $file"
            or die "An error ocurred when trying to open file: '$file'\n";
         my $output = <FILE>;
         close FILE
            or die "An error ocurred when trying to close file: '$file'\n";
         return $output;
      },
      delete_file => q{
         my ($file) = @_;
         unlink $file;
      }
   );
   
   $self->{MACHINE} = $machine;
}

sub execute_preamble {
   my $self = shift;

   # PREAMBLE es llamada y provista de la funcionalidad
   # de la clase GRID::Machine correspondiente
   # 
   my $result = $self->{PREAMBLE}->($self->{MACHINE});
   $self->{MACHINE}->chdir($self->{WORKDIR}) if $self->{WORKDIR};
   return $result;
}

sub execute_postamble {
   my $self = shift;
   $self->{POSTAMBLE}->($self->{MACHINE});
}

sub get_result {
   return $_[0]->{GET_RESULT}->(@_);
}

sub default_get_result {
   my ($self, $params) = (shift, shift);

   my $m = $self->{MACHINE};
   my $executable = $self->{EXECUTABLE};

   my $output = $m->execute_file($executable, $params)->result;

   if (my $outputfile = $self->{OUTPUTFILE}) {
      $m->can_read($outputfile)->result
         or die "File '$outputfile' doesn't exists or permission denied\n";
      $output = $m->read_file($outputfile)->result
         or die "An error ocurred when trying to read file: '$outputfile'\n";
      $m->delete_file($outputfile)->result
         or die "An error ocurred when trying to delete file: '$outputfile'\n";
   }
   return $output;
}

sub save_result {
   return $_[0]->{SAVE_RESULT}->(@_);
}

sub default_save_result {
   my ($self, $params, $test) = @_;

   my $output = $self->get_result($params);

   if (not -d $self->{BASEDIR}) {
      mkdir $self->{BASEDIR};
      print "Creating directory for base files: " . $self->{BASEDIR} . "\n";
   }

   chdir $self->{BASEDIR};

   open BASEFILE, "> $test.base";
   print BASEFILE $output;
   close BASEFILE;

   print "Created " . $self->{BASEDIR} . "/$test.base\n";
  
   chdir $self->{CURRENTDIR};
}
